testsuite: Add an incremental sort test
authorMatthias Clasen <mclasen@redhat.com>
Fri, 24 Jul 2020 22:32:01 +0000 (18:32 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Fri, 24 Jul 2020 23:23:18 +0000 (19:23 -0400)
Add a test that makes changes to a model while it
is incrementally sorted.

testsuite/gtk/sortlistmodel.c

index 10eccfadaa583770cab054f0964af08b66c2df63..1da5c3d815d7ccc0fc2b6b655ae8bd7731c0c59c 100644 (file)
@@ -91,6 +91,22 @@ add (GListStore *store,
   g_object_unref (object);
 }
 
+static void
+insert (GListStore *store,
+        guint       position,
+        guint       number)
+{
+  GObject *object;
+
+  /* 0 cannot be differentiated from NULL, so don't use it */
+  g_assert (number != 0);
+
+  object = g_object_new (G_TYPE_OBJECT, NULL);
+  g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
+  g_list_store_insert (store, position, object);
+  g_object_unref (object);
+}
+
 #define assert_model(model, expected) G_STMT_START{ \
   char *s = model_to_string (G_LIST_MODEL (model)); \
   if (!g_str_equal (s, expected)) \
@@ -107,6 +123,11 @@ add (GListStore *store,
   g_string_set_size (changes, 0); \
 }G_STMT_END
 
+#define ignore_changes(model) G_STMT_START{ \
+  GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
+  g_string_set_size (changes, 0); \
+}G_STMT_END
+
 static GListStore *
 new_empty_store (void)
 {
@@ -398,7 +419,7 @@ test_stability (void)
   GtkSortListModel *sort;
   GListStore *store;
   GtkSorter *sorter;
-  
+
   store = new_store ((guint[]) { 11, 31, 21, 1, 0 });
   sort = new_model (store);
   assert_model (sort, "1 11 21 31");
@@ -414,6 +435,89 @@ test_stability (void)
   g_object_unref (sort);
 }
 
+static GListStore *
+new_shuffled_store (guint size)
+{
+  GListStore *store = new_empty_store ();
+  guint i;
+
+  add (store, 1);
+
+  for (i = 1; i < size; i++)
+    insert (store, g_random_int_range (0, i), i + 1);
+
+  return store;
+}
+
+/* Test that we don't crash when things are removed from the
+ * model while it is incrementally sorting.
+ */
+static void
+test_incremental_remove (void)
+{
+  GListStore *store;
+  GtkSortListModel *model;
+  GtkSorter *sorter;
+  guint i;
+  GListStore *removed;
+  const guint n_items = 100000;
+
+  store = new_shuffled_store (n_items);
+  model = new_model (NULL);
+  gtk_sort_list_model_set_incremental (model, TRUE);
+
+  gtk_sort_list_model_set_model (model, G_LIST_MODEL (store));
+
+  sorter = gtk_custom_sorter_new (compare, NULL, NULL);
+  gtk_sort_list_model_set_sorter (model, sorter);
+  g_object_unref (sorter);
+
+  removed = g_list_store_new (G_TYPE_OBJECT);
+
+  while (gtk_sort_list_model_get_pending (model) != 0)
+    {
+      g_main_context_iteration (NULL, TRUE);
+
+      /* randomly remove items while the sort is ongoing */
+      if (g_list_model_get_n_items (G_LIST_MODEL (removed)) < 100)
+        {
+          guint position;
+
+          position = g_random_int_range (0, g_list_model_get_n_items (G_LIST_MODEL (store)) - 10);
+          for (i = 0; i < 10; i++)
+            {
+              GObject *item = g_list_model_get_item (G_LIST_MODEL (store), position + i);
+              g_list_store_append (removed, item);
+              g_object_unref (item);
+            }
+          g_list_store_splice (store, position, 10, NULL, 0);
+        }
+    }
+
+  g_assert_cmpuint (gtk_sort_list_model_get_pending (model), ==, 0);
+
+  gtk_sort_list_model_set_incremental (model, FALSE);
+
+  /* add them back */
+  for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (removed)); i++)
+    {
+      GObject *item = g_list_model_get_item (G_LIST_MODEL (removed), i);
+      g_list_store_append (store, item);
+      g_object_unref (item);
+    }
+
+  g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (model)), ==, n_items);
+
+  for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (model)); i++)
+    g_assert_cmpuint (i + 1, ==, get (G_LIST_MODEL (model), i));
+
+  ignore_changes (model);
+
+  g_object_unref (store);
+  g_object_unref (model);
+  g_object_unref (removed);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -432,6 +536,7 @@ main (int argc, char *argv[])
   g_test_add_func ("/sortlistmodel/remove_items", test_remove_items);
 #endif
   g_test_add_func ("/sortlistmodel/stability", test_stability);
+  g_test_add_func ("/sortlistmodel/incremental/remove", test_incremental_remove);
 
   return g_test_run ();
 }